package com.briup.pai.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.briup.pai.common.constant.DictionaryConstant;
import com.briup.pai.common.enums.ResultCodeEnum;
import com.briup.pai.common.exception.BriupAssert;
import com.briup.pai.convert.DictionaryConvert;
import com.briup.pai.dao.DictionaryMapper;
import com.briup.pai.entity.dto.DictionarySaveDTO;
import com.briup.pai.entity.po.Dictionary;
import com.briup.pai.entity.vo.DictionaryEchoVO;
import com.briup.pai.entity.vo.DictionaryPageVO;
import com.briup.pai.entity.vo.DropDownVO;
import com.briup.pai.entity.vo.PageVO;
import com.briup.pai.service.IDictionaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@CacheConfig(cacheNames = DictionaryConstant.DICTIONARY_CACHE_PREFIX)
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements IDictionaryService {

    @Autowired
    private DictionaryMapper dictionaryMapper;
    @Autowired
    private DictionaryConvert dictionaryConvert;

    @Override
    @CachePut(key = "#result.dictId")
    public DictionaryEchoVO addOrModifyDictionary(DictionarySaveDTO dto) {
        // 对象转换（获得数据转换为po）
        Dictionary dictionary = dictionaryConvert.dictionarySaveDTO2PO(dto);

        // 根据dto中是否存在id判断是新增还是修改操作
        if (dictionary.getId() != null) {
            // 修改（除了数据校验之外，dictCode不允许修改）
            dictionary.setDictCode(null);
            dictionary.setParentId(null);
            dictionaryMapper.updateById(dictionary);
        } else{
            // 新增
            dictionaryMapper.insert(dictionary);
            // 插入成功后返回主键，根据主键再查询一个po
            // 对象转换（实体类的po转换为展示用的vo）
        }
        return getDictionaryById(dictionary.getId());
    }

    @Override
    @Cacheable(key = "#dictionaryId")
    public DictionaryEchoVO getDictionaryById(Integer dictionaryId) {
        // 要求验证数据字典不为空，使用自定义断言
        Dictionary dictionary = BriupAssert.requireNotNull(this, Dictionary::getId, dictionaryId, ResultCodeEnum.DATA_NOT_EXIST);
        return dictionaryConvert.po2DictionaryEchoVO(dictionary);
    }

    @Override
    @CacheEvict(allEntries = true)
    public void removeDictionaryById(Integer dictionaryId) {
        // 根据id删除数据字典
        /*
        要求1：删除一级字典时，同步删除所有的二级字典
        要求2：删除二级字典后，如果一级字典下没有二级字典了，同步删除一级字典
         */

        // 根据dictionaryId查询并做参数校验
        Dictionary dictionary = BriupAssert.requireNotNull(this, Dictionary::getId, dictionaryId, ResultCodeEnum.DATA_NOT_EXIST);
        // 获取数据字典的父id
        Integer parentId = dictionary.getParentId();
        // 准备条件构造器
        LambdaQueryWrapper<Dictionary> deleteWrapper = new LambdaQueryWrapper<>();
        // 判断该对象是几级数据字典
        if (ObjectUtil.equal(parentId, DictionaryConstant.PARENT_DICTIONARY_ID)) {
            // dictionary为一级字典
            // 表中都是逻辑外键，不存在及联的关系
            // 先删除二级字典
            deleteWrapper.eq(Dictionary::getParentId, dictionaryId);
            dictionaryMapper.delete(deleteWrapper);
            // 再删除一级字典
            dictionaryMapper.deleteById(dictionaryId);
        }else {
            // 二级字典
            // 直接删除
            dictionaryMapper.deleteById(dictionaryId);
            // 判断一级字典下是否还有二级字典
            // 查询父id下的数据个数为0，就删掉
            deleteWrapper.clear();
            deleteWrapper.eq(Dictionary::getParentId, parentId);
            // count的返回值类型long，注意类型保持一致
            if (ObjectUtil.equal(this.count(deleteWrapper),0L)) {
                dictionaryMapper.deleteById(parentId);
            }
        }
    }

    @Override
    public PageVO<DictionaryPageVO> getDictionaryByPage(Long pageNum, Long pageSize) {

        // 准备分页对象
        Page<Dictionary> page = new Page<>(pageNum,pageSize);
        // 准备结果
        PageVO<DictionaryPageVO> result = new PageVO<>();
        // 查询（查两遍，先查带分页的一级数据字典，再根据结果查所有的二级数据字典）
        // 查询所有的一级数据字典，带分页
        LambdaQueryWrapper<Dictionary> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Dictionary::getParentId, DictionaryConstant.PARENT_DICTIONARY_ID);
        Page<Dictionary> onePage = dictionaryMapper.selectPage(page, lqw);
        result.setTotal(onePage.getTotal());
        result.setData(dictionaryConvert.po2DictionaryPageVOList(onePage.getRecords())
                .stream().peek(dictionaryPageVO -> {
                    // 根据vo的id查询出所有的二级字典
                    lqw.clear();
                    lqw.eq(Dictionary::getParentId, dictionaryPageVO.getDictId());
                    // 只对一级字典做分页，二级直接查全部
                    List<Dictionary> secondList = dictionaryMapper.selectList(lqw);
                    // 转换成vo对象
                    List<DictionaryPageVO> secondePageVOS = dictionaryConvert.po2DictionaryPageVOList(secondList);
                    dictionaryPageVO.setChildren(secondePageVOS);
                }).toList());

        return result;
    }

    @Override
    @Cacheable(key = "T(com.briup.pai.common.constant.CommonConstant).DROPDOWN_CACHE_PREFIX+':'+#dictCode",
               unless = "#result == null")
    public List<DropDownVO> getDropDownList(String dictCode) {
        // 数据字典必须存在
        Dictionary dictionary = BriupAssert.requireNotNull(this, Dictionary::getDictCode, dictCode, ResultCodeEnum.PARAM_IS_ERROR);
        // 数据字典必须是一级数据字典
        BriupAssert.requireIn(dictionary.getId(),getParentIdList(), ResultCodeEnum.PARAM_IS_ERROR);
        // 查询该1级字典所有的2级字典
        LambdaQueryWrapper<Dictionary> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Dictionary::getParentId, dictionary.getId());
        // 转换并返回
        return dictionaryConvert.po2DictionaryDropDownVOList(this.list(lqw));
    }

    @Override
    @Cacheable(key = "T(com.briup.pai.common.constant.DictionaryConstant).DICTIONARY_CACHE_PREFIX+':'+#dictionaryId",
               unless = "#result == ''")
    public String getDictionaryValueById(Integer dictionaryId) {
        // 先查处出来
        Dictionary dictionary = this.getById(dictionaryId);
        return ObjectUtil.isNotNull(dictionary) ? dictionary.getDictValue() : "";
    }

    /**
     * 获取所有的一级数据字典的id值
     * @return java.util.List<java.lang.Integer>
     */
    private List<Integer> getParentIdList(){
        LambdaQueryWrapper<Dictionary> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Dictionary::getParentId, DictionaryConstant.PARENT_DICTIONARY_ID);
        return dictionaryMapper.selectList(lqw).stream().map(Dictionary::getId).toList();
    }
}